/* 
 * File:   Constraint.h
 * Author: jcrada
 *
 * Created on December 15, 2008, 2:49 PM
 */

#ifndef _CONSTRAINT_H
#define	_CONSTRAINT_H

#include "BodyPart.h"
#include "Creature.h"
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>

namespace jcrada {

    class Creature;

    class Constraint {
    public:
        static const int MAX_CONNECTION_POINTS;
        static const double G6DOF_MIN_ANGLE_X;
        static const double G6DOF_MIN_ANGLE_Y;
        static const double G6DOF_MIN_ANGLE_Z;
        static const double G6DOF_MAX_ANGLE_X;
        static const double G6DOF_MAX_ANGLE_Y;
        static const double G6DOF_MAX_ANGLE_Z;
        static const double HINGE_MIN_LIMIT;
        static const double HINGE_MAX_LIMIT;
        static const double CONE_MIN_SWING;
        static const double CONE_MAX_SWING;
        static const double CONE_MIN_TWIST;
        static const double CONE_MAX_TWIST;

        enum eConstraintType {
            CT_GENERIC_6DOF = -2, CT_SLIDER, CT_CONE_TWIST, CT_HINGE, CT_POINT_TO_POINT, CT_COUNT
        };

        enum eConnection {
            NO_CONNECTION = -1,
        };

        enum eBoxConnectionPoints {
            BOX_TOP = 0,
            BOX_TOP_BACK, BOX_TOP_BACK_RIGHT, BOX_TOP_RIGHT, BOX_TOP_FRONT_RIGHT,
            BOX_TOP_FRONT, BOX_TOP_FRONT_LEFT, BOX_TOP_LEFT, BOX_TOP_BACK_LEFT,
            BOX_MID_BACK, BOX_MID_RIGHT, BOX_MID_FRONT, BOX_MID_LEFT,
            BOX_BOT_BACK, BOX_BOT_BACK_RIGHT, BOX_BOT_RIGHT, BOX_BOT_FRONT_RIGHT,
            BOX_BOT_FRONT, BOX_BOT_FRONT_LEFT, BOX_BOT_LEFT, BOX_BOT_BACK_LEFT,
            BOX_BOTTOM,
            BOX_CONNECTION_POINTS,
        };

        enum eSphereConnectionPoints {
            SPHERE_TOP = 0,
            SPHERE_R1_BACK, SPHERE_R1_RIGHT, SPHERE_R1_FRONT, SPHERE_R1_LEFT,
            SPHERE_R2_BACK_LEFT, SPHERE_R2_BACK_RIGHT, SPHERE_R2_FRONT_RIGHT, SPHERE_R2_FRONT_LEFT,
            SPHERE_R3_BACK, SPHERE_R3_RIGHT, SPHERE_R3_FRONT, SPHERE_R3_LEFT,
            SPHERE_R4_BACK_LEFT, SPHERE_R4_BACK_RIGHT, SPHERE_R4_FRONT_RIGHT, SPHERE_R4_FRONT_LEFT,
            SPHERE_R5_BACK, SPHERE_R5_RIGHT, SPHERE_R5_FRONT, SPHERE_R5_LEFT,
            SPHERE_BOTTOM,
            SPHERE_CONNECTION_POINTS,
        };

        enum eCylinderConnectionPoints {
            CYLINDER_TOP = 0,
            CYLINDER_R1_BACK, CYLINDER_R1_RIGHT, CYLINDER_R1_FRONT, CYLINDER_R1_LEFT,
            CYLINDER_R2_BACK, CYLINDER_R2_RIGHT, CYLINDER_R2_FRONT, CYLINDER_R2_LEFT,
            CYLINDER_R3_BACK, CYLINDER_R3_RIGHT, CYLINDER_R3_FRONT, CYLINDER_R3_LEFT,
            CYLINDER_R4_BACK, CYLINDER_R4_RIGHT, CYLINDER_R4_FRONT, CYLINDER_R4_LEFT,
            CYLINDER_R5_BACK, CYLINDER_R5_RIGHT, CYLINDER_R5_FRONT, CYLINDER_R5_LEFT,
            CYLINDER_BOTTOM,
            CYLINDER_CONNECTION_POINTS,
        };

        enum eConeConnectionPoints {
            CONE_TOP = 0,
            CONE_MID_BACK, CONE_MID_BACK_RIGHT, CONE_MID_RIGHT, CONE_MID_FRONT_RIGHT,
            CONE_MID_FRONT, CONE_MID_FRONT_LEFT, CONE_MID_LEFT, CONE_MID_BACK_LEFT,
            CONE_BOT_FRONT, CONE_BOT_FRONT_RIGHT, CONE_BOT_RIGHT, CONE_BOT_BACK_RIGHT,
            CONE_BOT_BACK, CONE_BOT_BACK_LEFT, CONE_BOT_LEFT, CONE_BOT_FRONT_LEFT,
            CONE_BOT_BACK_LEFT_2, CONE_BOT_BACK_RIGHT_2, CONE_BOT_FRONT_RIGHT_2, CONE_BOT_FRONT_LEFT_2,
            CONE_BOTTOM,
            CONE_CONNECTION_POINTS,
        };

    private:
        int _id;
        std::string _name;
        eConstraintType _type;
        btTypedConstraint *_constraint;
        int _id_body_a;
        int _id_body_b;
        int _connection_a;
        int _connection_b;
        double _hinge_lower_limit;
        double _hinge_upper_limit;
        btVector3 _linear_lower_limits;
        btVector3 _linear_upper_limits;
        btVector3 _angular_lower_limits;
        btVector3 _angular_upper_limits;
        double _cone_swing_x;
        double _cone_twist_y;
        double _cone_swing_z;

    protected:
        //        CT_GENERIC_6DOF = 0, CT_CONE_TWIST, CT_HINGE, CT_POINT_TO_POINT, CT_COUNT
        virtual btGeneric6DofConstraint* createGeneric6DofConstraint(const Creature& creature, bool use_linear_reference_frame_a = true);
        virtual btHingeConstraint* createHingeConstraint(const Creature& creature, bool use_linear_reference_frame_a = true);
        virtual btConeTwistConstraint* createConeTwistConstraint(const Creature& creature);
        virtual btPoint2PointConstraint* createPointToPointConstraint(const Creature& creature);
        virtual btSliderConstraint* createSliderConstraint(const Creature& creature, bool use_linear_reference_frame_a = true);

    public:
        static void locateConnectionOrigin(const BodyPart& body, int connection, btTransform& transform);
        static void locateBoxConnection(const BodyPart& body, int connection, btTransform& transform);
        static void locateSphereConnection(const BodyPart& body, int connection, btTransform& transform);
        static void locateCylinderConnection(const BodyPart& body, int connection, int axis, btTransform& transform);
        static void locateCapsuleConnection(const BodyPart& body, int connection, int axis, btTransform& transform);
        static void locateConeConnection(const BodyPart& body, int connection, int axis, btTransform& transform);

        Constraint();
        virtual ~Constraint();

        virtual void set(const Creature& creature);
        virtual void reset();

        virtual Constraint* clone() const;

        static Constraint* fromXml(const QDomElement& xml, bool* ok);
        virtual void toXml(QDomDocument& xml, QDomElement* parent = NULL) const;
        virtual std::string toXml() const;

        virtual void setId(int id) {
            this->_id = id;
        }

        virtual int getId() const {
            return this->_id;
        }

        virtual void setName(const std::string& name) {
            this->_name = name;
        }

        virtual std::string getName() const {
            return this->_name;
        }

        virtual void setType(eConstraintType type) {
            this->_type = type;
        }

        virtual eConstraintType getType() const {
            return this->_type;
        }

        virtual void setConstraint(btTypedConstraint* constraint) {
            this->_constraint = constraint;
        }

        virtual btTypedConstraint* getConstraint() const {
            return this->_constraint;
        }

        virtual void setIdBodyA(int id) {
            this->_id_body_a = id;
        }

        virtual int getIdBodyA() const {
            return this->_id_body_a;
        }

        virtual void setIdBodyB(int id) {
            this->_id_body_b = id;
        }

        virtual int getIdBodyB() const {
            return this->_id_body_b;
        }

        virtual void setConnectionA(int connection) {
            this->_connection_a = connection;
        }

        virtual int getConnectionA() const {
            return this->_connection_a;
        }

        virtual void setConnectionB(int connection) {
            this->_connection_b = connection;
        }

        virtual int getConnectionB() const {
            return this->_connection_b;
        }

        virtual void setLinearLowerLimits(const btVector3& limits) {
            this->_linear_lower_limits = limits;
        }

        virtual btVector3 getLinearLowerLimits() const {
            return this->_linear_lower_limits;
        }

        virtual void setLinearUpperLimits(const btVector3& limits) {
            this->_linear_upper_limits = limits;
        }

        virtual btVector3 getLinearUpperLimits() const {
            return this->_linear_upper_limits;
        }

        virtual void setAngularLowerLimits(const btVector3& limits) {
            this->_angular_lower_limits = limits;
        }

        virtual btVector3 getAngularLowerLimits() const {
            return this->_angular_lower_limits;
        }

        virtual void setAngularUpperLimits(const btVector3& limits) {
            this->_angular_upper_limits = limits;
        }

        virtual btVector3 getAngularUpperLimits() const {
            return this->_angular_upper_limits;
        }

        virtual void setLinearLowerUpperLimits(const btVector3& lower, const btVector3& upper) {
            setLinearLowerLimits(lower);
            setLinearUpperLimits(upper);
        }

        virtual void setAngularLowerUpperLimits(const btVector3& lower, const btVector3& upper) {
            setAngularLowerLimits(lower);
            setAngularUpperLimits(upper);
        }

        virtual void setHingeLowerLimit(double limit) {
            this->_hinge_lower_limit = limit;
        }

        virtual double getHingeLowerLimit() const {
            return this->_hinge_lower_limit;
        }

        virtual void setHingeUpperLimit(double limit) {
            this->_hinge_upper_limit = limit;
        }

        virtual double getHingeUpperLimit() const {
            return this->_hinge_upper_limit;
        }

        virtual void setConeSwingX(double limit) {
            this->_cone_swing_x = limit;
        }

        virtual double getConeSwingX() const {
            return this->_cone_swing_x;
        }

        virtual void setConeTwistY(double limit) {
            this->_cone_twist_y = limit;
        }

        virtual double getConeTwistY() const {
            return this->_cone_twist_y;
        }

        virtual void setConeSwingZ(double limit) {
            this->_cone_swing_z = limit;
        }

        virtual double getConeSwingZ() const {
            return this->_cone_swing_z;
        }


    };

}

#endif	/* _CONSTRAINT_H */

